home *** CD-ROM | disk | FTP | other *** search
- /* -*- C -*-
- * MAIN.C
- *
- * (c)Copyright 1991-93 by Tobias Ferber, All Rights Reserved
- */
-
- #include <stdarg.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
-
- #include "cvt.h"
- #include "filecopy.h"
-
-
- /*** / GLOBALS / ***/
-
- int global_numchars= 256; /* #of different chars in the local charset.
- * This number is also used to decide whether
- * an octal character code in a string runs
- * out of range */
-
- int global_maxhexdigits= 2; /* max. #of hexadecimal digits needed to express
- * 'global_numchars' */
- int global_maxoctdigits= 3; /* max. #of octal digits needed to express
- * 'global_numchars */
-
- int global_numerrors= 0; /* global error counter */
- int global_maxerrors= 5; /* #of errors until we abort */
- int global_checkexists= 0; /* flag for read_flist() */
- char *whoami; /* copy of argv[0] */
-
- /* input, output and error stream */
- FILE *fin, *fout, *ferr;
-
- #ifdef DEBUG
- int debuglevel;
- #endif
-
- static void display_version_information(void)
- {
- puts("CVT Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
- "(c)Copyright 1991-93 by Tobias Ferber, All Rights Reserved.\n");
- }
-
-
- /*** / MAIN / ***/
-
- void main(int argc, char *argv[])
- {
- char *rulefile, *outfmt, *errfile, *tmpfile;
-
- int badopt, err, dryrun, silent;
- fnode_t *fn;
-
- #ifdef _DCC /* Dice */
- expand_args(argc,argv, &argc,&argv);
- #endif /* _DCC */
-
- /* initialize globals */
-
- rulefile= outfmt= errfile= tmpfile= (char *)0L;
- badopt= err= dryrun= silent= 0;
-
- #ifdef __MSDOS__
-
- /* filenames on MS-DOG systems look very ugly: all uppercase and
- * backslashes. Perform some cosmetics. */
-
- whoami= "cvt";
-
- #else /* !__MSDOS__ */
- whoami= argv[0];
-
- #endif /* __MSDOS__ */
-
- fin = stdin;
- fout = stdout;
- ferr = stderr;
-
- while(--argc>0 && !badopt)
- {
- char *arg= *++argv;
-
- if(*arg=='-')
- {
- if(arg[1]=='-')
- arg= convert_args(*argv);
-
- switch(*++arg)
- {
-
- /*-c*/ case 'c':
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- if(arg && *arg)
- { int r= atoi(arg);
- if(0<r) global_numchars= r;
- else echo("iIllegal charset size: %d"
- " (using `-c%d')",r,global_numchars);
-
- global_maxhexdigits= numdigits(global_numchars, 0x10);
- global_maxoctdigits= numdigits(global_numchars, 010);
- }
- else
- { echo("missing charset size after `%s' option",*argv);
- ++badopt;
- }
- break;
-
- /*-d*/ case 'd':
-
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- #ifdef DEBUG
- if(arg && *arg)
- { debuglevel= atoi(arg);
- if(debuglevel < 0 || debuglevel > 4)
- { echo("debug level %d is not in [0..4]. (using `-d1')",
- debuglevel,*argv);
- debuglevel= 1;
- }
- }
- else
- { echo("missing debug level after `%s' option.",*argv);
- ++badopt;
- }
- #else
- echo("not compiled w/ -DDEBUG. No debug information available -- Sorry.");
- /* no error */
-
- #endif /* DEBUG */
-
- break;
-
- /*-E*/ case 'E':
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- if(arg && *arg)
- { if(errfile)
- { echo("option `%s' has already been seen!",*argv);
- echo("more than one error filename in your command line");
- ++badopt;
- }
- else errfile= arg;
- }
- else
- { echo("missing filename after `%s' option",*argv);
- ++badopt;
- }
- break;
-
- /*-e*/ case 'e':
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- if(arg && *arg)
- { int e= atoi(arg);
- if(0<e) global_maxerrors= e;
- else echo("illegal maximum #of errors: %d"
- " (using `-e%d')",e,global_maxerrors);
- }
- else
- { echo("missing maximum #of errors after `%s' option",*argv);
- ++badopt;
- }
- break;
-
- /*-f*/ case 'f':
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- if(arg && *arg)
- { if(rulefile)
- { echo("option `%s' has already been seen!",*argv);
- echo("more than one script filename in your command line");
- ++badopt;
- }
- else rulefile= arg;
- }
- else
- { echo("missing filename after `%s' option",*argv);
- ++badopt;
- }
- break;
-
- /*-?*/ case '?':
- /*-h*/ case 'h':
- fprintf(stderr,
- "usage: %s [options] [-f rulefile] [-o outfile] [infiles]\n\n",
- whoami);
-
- display_args();
- badopt= 1; /* hack: means exit. */
- break;
-
- /*-l*/ case 'l':
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- if(arg && *arg)
- {
- if( read_flist(arg) != 0)
- ++badopt;
- }
- else
- { echo("missing filename after `%s' option",*argv);
- ++badopt;
- }
- break;
-
- /*-n*/ case 'n':
- dryrun= 1;
- break;
-
- /*-o*/ case 'o':
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- if(arg && *arg)
- {
- if(outfmt)
- { echo("option `%s' has already been seen!",*argv);
- echo("more than one output filename in your command line");
- ++badopt;
- }
- else outfmt= arg;
- }
- else
- { echo("missing output filename after `%s' option",*argv);
- ++badopt;
- }
- break;
-
- /*-s*/ case 's':
- silent= 1;
- break;
-
- /*-t*/ case 't':
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- if(arg && *arg)
- { if(tmpfile)
- { echo("option `%s' has already been seen!",*argv);
- echo("more than one temporary output filename in your command line");
- ++badopt;
- }
- else
- { if( tmpfile= (char *)malloc((strlen(arg)+1) * sizeof(char)) )
- strcpy(tmpfile,arg);
- else
- { echo("out of memory... aaaiiiiiieeeeeeeee!");
- badopt= 103;
- }
- }
- }
- else
- { echo("missing filename after `%s' option",*argv);
- ++badopt;
- }
- break;
-
- /*-v*/ case 'v':
- display_version_information();
- break;
-
- /*-x*/ case 'x':
- global_checkexists= 1;
- break;
-
- /*??*/ default:
- echo("unrecognized option `%s'",*argv);
- badopt++;
- break;
- }
- }
- else if(*arg=='@')
- {
- if(arg[1]) ++arg;
- else arg= (--argc > 0) ? *(++argv) : (char *)0L;
-
- if(arg && *arg)
- {
- if( read_flist(arg) != 0)
- ++badopt;
- }
- else
- { echo("missing filename after `%s'",*argv);
- ++badopt;
- }
- }
- else
- {
- if(global_checkexists)
- {
- FILE *fp= fopen(arg,"r");
-
- if(fp)
- fclose(fp);
-
- else
- { perror(arg);
- ++badopt;
- }
- }
-
- if(!badopt)
- {
- if( chain_fname(0L,arg) )
- {
- echo("out of memory... bzzzzzzzz!");
- ++badopt;
- }
- }
- }
- }
-
- if(!badopt)
- {
- FILE *fp;
-
- #ifdef DEBUG
- if(debuglevel >= 1)
- print_flist();
- #endif
-
- /*
- * open error stream
- */
-
- if(errfile)
- {
- if( !(ferr= fopen(errfile,"w")) )
- { perror(errfile);
- echo("can't direct error output to `%s' -- will use stderr",
- errfile);
- ferr= stderr;
- }
- }
-
- err= init_rules();
-
- if(!err)
- {
- /*
- * In --dryrun mode the explicit use of the --file keyword
- * is not needed. Instead we treat all input files as script
- * files and try to parse them respectively.
- * If however there was a --file <rulefile> in the command-line
- * we will ignore futher input files (if any).
- */
-
- if(dryrun)
- {
- if(rulefile)
- {
-
- #ifdef DEBUG
- if(flist) /* global_numfiles is >= 1 */
- { echo("debug-warning: %d input files ignored.\n"
- "(They make no sense w/ options --dryrun --file \"%s\")",
- global_numfiles, rulefile );
- }
- #endif /* DEBUG */
-
- if( fp= cvtopen(rulefile) )
- {
- err= parsefile(fp);
- fclose(fp);
- }
- else perror(rulefile);
- }
- else /* !rulefile */
- {
- if(flist) /* global_numfiles is >= 1 */
- {
- fnode_t *fn;
-
- for(fn= flist; fn && !err; fn= fn->next)
- {
- if( fp= cvtopen(rulefile= fn->filename) )
- {
- err= parsefile(fp);
- fclose(fp);
-
- if(!err && fn->next)
- {
- fprintf(ferr, "%s: %d rules, no errors.\n",
- rulefile, global_numrules);
-
- exit_rules();
- err= init_rules();
- }
- }
- else err++;
- }
- }
- else /* !flist */
- { rulefile= "stdin"; /* filename for messages */
- err= parsefile(stdin);
- }
- }
- }
- else /* !dryrun */
- {
- if(rulefile)
- fp= cvtopen(rulefile);
- else
- { echo("warning: no conversion file... copying...");
- fp= (FILE *)0L;
- }
-
- if(fp)
- {
- err= parsefile(fp);
-
- if(fp!=stdin)
- fclose(fp);
-
- if(!err)
- {
- #ifdef DEBUG
- if(debuglevel >= 3)
- dump_crules();
- #endif
- if(global_numrules==0)
- { echo("warning: file '%s' contains no rules... copying...",
- rulefile);
- }
- }
- }
- else if(rulefile)
- { echo("no conversion file similar or equal to `%s' -- Sorry.",
- rulefile);
- err= 1;
- }
- }
- }
- else
- { echo("not enough memory for a %d character charset!", global_numchars);
- err= 1;
- }
- }
- else /* badopt != 0 */
- err= 1;
-
- /*
- * convert
- */
-
- fn= flist;
-
- if(!dryrun && !err) do
- {
- char *infile, *outfile= (char *)0L;
-
- if(fn)
- {
- infile= fn->filename;
-
- if( !(fin= fopen(infile,"rb")) )
- { perror(infile);
- echo("can't access your input file `%s'",infile);
- err= 1;
- }
- }
- else
- { infile= "stdin";
- fin= stdin;
- }
-
- if(!err)
- {
- if(outfmt)
- {
- outfile= (char *)malloc(strlen(infile)+strlen(outfmt));
-
- if(!tmpfile)
- tmpfile= tfname(TEMPFILE_FORMAT);
-
- if(!outfile || !tmpfile)
- {
- echo("out of memory... aaaaarrrgggghhhh!");
- err= 1;
- }
- else
- {
- sprintf(outfile,outfmt,infile);
-
- if(!silent)
- printf(" %s\n",outfile);
-
- #ifdef DEBUG
- if(debuglevel >= 1)
- printf("%d chars for output filename `%s' allocated,\n"
- "writing temporary data on `%s'.\n",
- strlen(infile)+strlen(outfmt), outfile, tmpfile);
- #endif /* DEBUG */
- }
- }
- else outfile= (char *)0L; /* use stdout */
-
- /* Wenn wir nach stdout konvertieren sollen, dann brauchen wir
- * kein tempor"ares File, denn wenn wir an die console schicken
- * machen wir eh' nix kaputt und wenn 'stdin' redirected ist,
- * hat die Shell das File auch schon zerschossen...
- * Wir tun dem Benutzer aber den Gefallen und puffern die Ausgabe
- * trotzdem, wenn er es explizit (mittels `-t' Option) w"unscht. */
-
- if(!err && tmpfile)
- {
- if( !(fout= fopen(tmpfile, "wb")) )
- { perror(tmpfile);
- echo("can't access temporary output file `%s'",tmpfile);
- err= 1;
- }
- }
- }
-
- if(!err)
- dothehardpart(); /* let's roll! */
-
- if(fin && fin!=stdin)
- fclose(fin);
-
- if(fout && fout!=stdout)
- fclose(fout);
-
- if(!err)
- {
- long n;
-
- /* Wenn wir in ein tempor"ares File geschrieben haben, (was immer
- * der Fall ist, wenn wir nicht nach stdout geschrieben haben)
- * dann m"ussen wir jetzt noch kopieren. Wir k"onnen das tmpfile
- * nicht einfach renamen, weil es nicht im aktuellen Verzeichnis
- * stehen mu\3. */
-
- if(outfile)
- {
- if(fin= fopen(tmpfile,"rb"))
- {
- if(fout= fopen(outfile,"wb"))
- {
- if( (n= filecopy(fin,fout,0L)) < 0L )
- {
- if(n==-1)
- { perror(tmpfile);
- echo("error reading temporary data from `%s'",tmpfile);
- }
- else
- { perror(outfile);
- echo("error writing output to `%s'",outfile);
- echo("temporary output written on `%s'",tmpfile);
- }
- err= 1;
- }
- #ifdef DEBUG
- else if(debuglevel >= 1)
- printf("%ld byte(s) of output\n",n);
- #endif
- fclose(fout);
- }
- else
- { perror(outfile);
- echo("can't write to `%s'",outfile);
- echo("temporary output written on `%s'",tmpfile);
- err= 1;
- }
- fclose(fin);
- }
- else
- { perror(tmpfile);
- echo("couldn't re-open temporary file `%s'",tmpfile);
- err= 1;
- }
- }
- else if(tmpfile) /* but !outfile */
- {
- FILE *fp;
-
- /* Wir haben in ein tempor"ares File geschrieben und m"ussen die
- * Ausgabe auf die Console umleiten. Wir machen das Zeichen f"ur
- * Zeichen... */
-
- if( fp= fopen(tmpfile, "rb") )
- { for(n=0; !feof(fp); n++)
- { char c= fgetc(fp);
- if(!feof(fp))
- fputc(c,stdout);
- }
- fclose(fp);
- }
- else
- { perror(tmpfile);
- echo("couldn't re-open temporary file");
- err= 1;
- }
- }
- /* otherwise we wrote to <stdout> directly */
- }
-
- if(tmpfile)
- { if(!err)
- remove(tmpfile);
- free(tmpfile);
- tmpfile= (char *)0L;
- }
-
- if(fn)
- fn= fn->next;
-
- if(outfile)
- { free(outfile);
- outfile= (char *)0L;
- }
-
- } while(fn && !err);
-
- if(err)
- { echo("*** [%s] exit code %d.",
- (rulefile && *rulefile) ? rulefile : "no rules", err);
- }
- else if(dryrun && rulefile)
- fprintf(ferr, "%s: %d rules, no errors.\n",rulefile, global_numrules);
-
- if(flist)
- purge_flist();
-
- if(crules)
- exit_rules();
-
- if(ferr && ferr!=stderr)
- fclose(ferr);
-
- exit(err ? 1:0);
- }
-